:art: Add wxa login

huangqimin001 2 年之前
父节点
当前提交
2665ca2642
共有 11 个文件被更改,包括 219 次插入1 次删除
  1. 0 0
      account/__init__.py
  2. 12 0
      account/admin.py
  3. 5 0
      account/apps.py
  4. 38 0
      account/migrations/0001_initial.py
  5. 0 0
      account/migrations/__init__.py
  6. 43 0
      account/models.py
  7. 4 0
      account/tests.py
  8. 4 0
      account/views.py
  9. 109 0
      api/mini_views.py
  10. 3 1
      api/urls.py
  11. 1 0
      tiwen/settings.py

+ 0 - 0
account/__init__.py


+ 12 - 0
account/admin.py

@@ -0,0 +1,12 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.contrib import admin
4
+
5
+from account.models import UserInfo
6
+
7
+
8
+class UserInfoAdmin(admin.ModelAdmin):
9
+    list_display = ('user_id', 'unionid', 'openid', 'nickname', 'sex', 'avatar', 'phone', 'country', 'province', 'city', 'status', 'created_at', 'updated_at')
10
+
11
+
12
+admin.site.register(UserInfo, UserInfoAdmin)

+ 5 - 0
account/apps.py

@@ -0,0 +1,5 @@
1
+from django.apps import AppConfig
2
+
3
+
4
+class AccountConfig(AppConfig):
5
+    name = 'account'

+ 38 - 0
account/migrations/0001_initial.py

@@ -0,0 +1,38 @@
1
+# Generated by Django 3.2.14 on 2022-07-05 10:31
2
+
3
+from django.db import migrations, models
4
+import shortuuidfield.fields
5
+
6
+
7
+class Migration(migrations.Migration):
8
+
9
+    initial = True
10
+
11
+    dependencies = [
12
+    ]
13
+
14
+    operations = [
15
+        migrations.CreateModel(
16
+            name='UserInfo',
17
+            fields=[
18
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
19
+                ('status', models.BooleanField(default=True, help_text='Status', verbose_name='status')),
20
+                ('created_at', models.DateTimeField(auto_now_add=True, help_text='Create Time', verbose_name='created_at')),
21
+                ('updated_at', models.DateTimeField(auto_now=True, help_text='Update Time', verbose_name='updated_at')),
22
+                ('user_id', shortuuidfield.fields.ShortUUIDField(blank=True, db_index=True, editable=False, help_text='用户唯一标识', max_length=22, null=True, unique=True)),
23
+                ('unionid', models.CharField(blank=True, db_index=True, help_text='微信 Unionid', max_length=32, null=True, unique=True, verbose_name='unionid')),
24
+                ('openid', models.CharField(blank=True, db_index=True, help_text='微信 Openid', max_length=32, null=True, unique=True, verbose_name='openid')),
25
+                ('nickname', models.CharField(blank=True, help_text='用户昵称', max_length=255, null=True, verbose_name='nickname')),
26
+                ('sex', models.IntegerField(choices=[(0, '未知'), (1, '男'), (2, '女')], default=0, help_text='用户性别', verbose_name='sex')),
27
+                ('avatar', models.CharField(blank=True, help_text='用户头像', max_length=255, null=True, verbose_name='avatar')),
28
+                ('phone', models.CharField(blank=True, db_index=True, help_text='用户电话', max_length=11, null=True, verbose_name='phone')),
29
+                ('country', models.CharField(blank=True, help_text='用户国家', max_length=255, null=True, verbose_name='country')),
30
+                ('province', models.CharField(blank=True, help_text='用户省份', max_length=255, null=True, verbose_name='province')),
31
+                ('city', models.CharField(blank=True, help_text='用户城市', max_length=255, null=True, verbose_name='city')),
32
+            ],
33
+            options={
34
+                'verbose_name': '用户信息',
35
+                'verbose_name_plural': '用户信息',
36
+            },
37
+        ),
38
+    ]

+ 0 - 0
account/migrations/__init__.py


+ 43 - 0
account/models.py

@@ -0,0 +1,43 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+from django.db import models
4
+from django.utils.translation import gettext_lazy as _
5
+from django_models_ext import BaseModelMixin, SexModelMixin
6
+from shortuuidfield import ShortUUIDField
7
+
8
+
9
+class UserInfo(BaseModelMixin):
10
+    user_id = ShortUUIDField(_('user_id'), max_length=32, blank=True, null=True, help_text='用户唯一标识', db_index=True, unique=True)
11
+    # 微信相关
12
+    unionid = models.CharField(_('unionid'), max_length=32, blank=True, null=True, help_text='微信 Unionid', db_index=True, unique=True)
13
+    openid = models.CharField(_('openid'), max_length=32, blank=True, null=True, help_text='微信 Openid', db_index=True, unique=True)
14
+    # 基本信息
15
+    nickname = models.CharField(_('nickname'), max_length=255, blank=True, null=True, help_text='用户昵称')
16
+    sex = models.IntegerField(_('sex'), choices=SexModelMixin.SEX_TUPLE, default=SexModelMixin.UNKNOWN, help_text='用户性别')
17
+    avatar = models.CharField(_('avatar'), max_length=255, blank=True, null=True, help_text='用户头像')
18
+    phone = models.CharField(_('phone'), max_length=11, blank=True, null=True, help_text='用户电话', db_index=True)
19
+    country = models.CharField(_('country'), max_length=255, blank=True, null=True, help_text='用户国家')
20
+    province = models.CharField(_('province'), max_length=255, blank=True, null=True, help_text='用户省份')
21
+    city = models.CharField(_('city'), max_length=255, blank=True, null=True, help_text='用户城市')
22
+
23
+    class Meta:
24
+        verbose_name = _('用户信息')
25
+        verbose_name_plural = _('用户信息')
26
+
27
+    def __unicode__(self):
28
+        return self.pk
29
+
30
+    @property
31
+    def data(self):
32
+        return {
33
+            'user_id': self.user_id,
34
+            'unionid': self.unionid,
35
+            'openid': self.openid,
36
+            'nickname': self.nickname,
37
+            'sex': self.sex,
38
+            'avatar': self.avatar,
39
+            'phone': self.phone,
40
+            'country': self.country,
41
+            'province': self.province,
42
+            'city': self.city,
43
+        }

+ 4 - 0
account/tests.py

@@ -0,0 +1,4 @@
1
+from django.test import TestCase
2
+
3
+
4
+# Create your tests here.

+ 4 - 0
account/views.py

@@ -0,0 +1,4 @@
1
+from django.shortcuts import render
2
+
3
+
4
+# Create your views here.

+ 109 - 0
api/mini_views.py

@@ -0,0 +1,109 @@
1
+# -*- coding: utf-8 -*-
2
+
3
+import logging
4
+
5
+from django.conf import settings
6
+from django.db import transaction
7
+from django_logit import logit
8
+from django_response import response
9
+from pywe_miniapp import get_session_info, get_session_key, get_userinfo, store_session_key
10
+from pywe_storage import RedisStorage
11
+
12
+from account.models import UserInfo
13
+from utils.redis.connect import r
14
+
15
+
16
+WECHAT = settings.WECHAT
17
+logger = logging.getLogger('logit')
18
+
19
+
20
+@logit(res=True)
21
+@transaction.atomic
22
+def mini_login_api(request):
23
+    wxcfg = WECHAT.get('MINIAPP', {})
24
+
25
+    appid = wxcfg.get('appID')
26
+    secret = wxcfg.get('appsecret')
27
+
28
+    code = request.POST.get('code', '')
29
+
30
+    # // 正常返回的JSON数据包
31
+    # {
32
+    #     "openid": "OPENID",
33
+    #     "session_key": "SESSIONKEY",
34
+    # }
35
+    #
36
+    # // 满足UnionID返回条件时,返回的JSON数据包
37
+    # {
38
+    #     "openid": "OPENID",
39
+    #     "session_key": "SESSIONKEY",
40
+    #     "unionid": "UNIONID"
41
+    # }
42
+    # // 错误时返回JSON数据包(示例为Code无效)
43
+    # {
44
+    #     "errcode": 40029,
45
+    #     "errmsg": "invalid code"
46
+    # }
47
+    session_info = get_session_info(appid=appid, secret=secret, code=code)
48
+    logger.debug(session_info)
49
+    session_key = session_info.get('session_key', '')
50
+    unionid = session_info.get('unionid', '')
51
+    openid = session_info.get('openid', '')
52
+
53
+    # Get or Create User
54
+    user, _ = UserInfo.objects.select_for_update().get_or_create(openid=openid)
55
+
56
+    # Set User Key's Value
57
+    if unionid:
58
+        user.unionid = unionid
59
+    user.save()
60
+
61
+    # Store SessionKey
62
+    store_session_key(appid=appid, secret=secret, session_key=session_key, unid=user.user_id, storage=RedisStorage(r))
63
+
64
+    return response(data=user.data)
65
+
66
+
67
+@logit
68
+@transaction.atomic
69
+def get_userinfo_api(request):
70
+    wxcfg = WECHAT.get('MINIAPP', {})
71
+
72
+    appid = wxcfg.get('appID')
73
+    secret = wxcfg.get('appsecret')
74
+
75
+    user_id = request.POST.get('user_id', '')
76
+    encryptedData = request.POST.get('encryptedData', '')
77
+    iv = request.POST.get('iv', '')
78
+
79
+    try:
80
+        user = UserInfo.objects.get(user_id=user_id, status=True)
81
+    except UserInfo.DoesNotExist:
82
+        return response()
83
+
84
+    # {u'avatarUrl': u'http://wx.qlogo.cn/mmopen/vi_32/aSKcBBPpibyKNicHNTMM0qJVh8Kjgiak2AHWr8MHM4WgMEm7GFhsf8OYrySdbvAMvTsw3mo8ibKicsnfN5pRjl1p8HQ/0',
85
+    #  u'city': u'Guangzhou',
86
+    #  u'country': u'CN',
87
+    #  u'gender': 1,
88
+    #  u'language': u'zh_CN',
89
+    #  u'nickName': u'Band',
90
+    #  u'openId': u'oGZUI0egBJY1zhBYw2KhdUfwVJJE',
91
+    #  u'province': u'Guangdong',
92
+    #  u'unionId': u'ocMvos6NjeKLIBqg5Mr9QjxrP1FA',
93
+    #  u'watermark': {u'appid': u'wx4f4bc4dec97d474b', u'timestamp': 1477314187}}
94
+    session_key = get_session_key(appid=appid, secret=secret, unid=user_id, storage=RedisStorage(r))
95
+    # Get Userinfo
96
+    userinfo = get_userinfo(appid=appid, secret=secret, session_key=session_key, encryptedData=encryptedData, iv=iv)
97
+
98
+    # Set User Key's Value
99
+    user.unionid = userinfo.get('unionId', '')
100
+    user.openid = userinfo.get('openId', '')
101
+    user.nickname = userinfo.get('nickName', '')
102
+    user.sex = userinfo.get('gender', '')
103
+    user.avatar = userinfo.get('avatarUrl', '')
104
+    user.country = userinfo.get('country', '')
105
+    user.province = userinfo.get('province', '')
106
+    user.city = userinfo.get('city', '')
107
+    user.save()
108
+
109
+    return response(data=user.data)

+ 3 - 1
api/urls.py

@@ -2,10 +2,12 @@
2 2
 
3 3
 from django.urls import re_path
4 4
 
5
-from api import oauth_views
5
+from api import mini_views, oauth_views
6 6
 
7 7
 
8 8
 urlpatterns = [
9
+    re_path(r'^mini/login$', mini_views.mini_login_api, name='mini_login_api'),  # 小程序登录
10
+    re_path(r'^mini/userinfo$', mini_views.get_userinfo_api, name='get_userinfo_api'),  # 获取用户信息
9 11
 ]
10 12
 
11 13
 urlpatterns += [

+ 1 - 0
tiwen/settings.py

@@ -56,6 +56,7 @@ INSTALLED_APPS = [
56 56
     'django_we',
57 57
     'commands',
58 58
     'api',
59
+    'account',
59 60
 ]
60 61
 
61 62
 MIDDLEWARE = [